/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "拾取.h"

#include <节点/插座/通用插座.h>
#include <节点/插座/C_物体插座.h>
#include <节点/插座/C_单值矢量插座.h>
#include <节点/插座/list/list矢量插座.h>


vec3	C_射线拾取节点::m_视口空间坐标[2] = {};





C_射线拾取节点::C_射线拾取节点(S_设备环境& ctx) : C_节点基类("射线拾取节点") {
	m_Name = L"射线拾取";
	m_GPU环境 = ctx;
	m_是否以视口射线拾取 = false;
	m_输入的数据类型 = E_值类型::e_Type_None;


	m_GPU可视网格 = f_surface_创建网格对象(nullptr, m_GPU环境, E_网格数据枚举::e_Mesh_VULKAN);
	m_GPU射线可视网格 = f_surface_创建网格对象(nullptr, m_GPU环境, E_网格数据枚举::e_Mesh_VULKAN);


	C_插座基类* socket;
	DEF_创建引用插座_I(L"容器");
	//DEF_引用插座创建_I("范围");
	DEF_创建Vec3_Array1D插座_I(L"射线");
	//DEF_创建Vec3插座_I("射线终点");


	DEF_创建树路径插座_O(L"拾取空间");
	DEF_创建引用插座_O(L"拾取");
	

}

C_射线拾取节点::~C_射线拾取节点() {

}

bool C_射线拾取节点::f_update() {
	auto& 输入数据 = *DEF_引用插座数据(f_get输入插座(1), 0);
	auto& 范围数据 = *DEF_Vec3_Array1D插座数据(f_get输入插座(2), 0);
	//auto 射线 = *DEF_取Vec3_1D插座数据(f_get输入插座(2), 0);
	//vec3 射线终点 = DEF_Vec3插座Value(f_get输入插座(3), 0);
	auto& 空间树 = *DEF_树路径插座Value(f_get输出插座(1), 0);

	bool 是否射线拾取 = false;
	//std::vector<S_VecSphere> 射线(2);
	vec3* 射线 = 范围数据.data();
	uint32 射线数量 = 范围数据.size() * 0.5;
	if (m_是否以视口射线拾取 || 射线数量 < 2) {
		//射线.resize(2);
		射线 = m_视口空间坐标;
		射线数量 = 1;

		f_surface_fill顶点数据(m_GPU射线可视网格, { m_视口空间坐标[0] , m_视口空间坐标[1] });
	}
	else {
		f_surface_fill顶点数据(m_GPU射线可视网格, 范围数据);
	}
	//vec3 dir = vec_normalize2(射线[1] - 射线[0]);
	vec3 dir;



	m_输入的数据类型 = 输入数据.m_Type;
	switch (输入数据.m_Type) {
	case E_值类型::e_插座Type_八叉树: {
		auto* tree = ((S_点距八叉树*)输入数据.m_Data);

		空间树.clear();
		std::vector<vec4> 空间坐标;
		for (uint32 k = 0; k < 射线数量; ++k) {
			f_空间划分_get射线子集数据(tree, 射线[k * 2], 射线[k * 2 + 1], 空间树);
			f_空间划分_射线拾取结果解析为域坐标(tree, 射线[k * 2], 射线[k * 2 + 1], 空间坐标);
		}
		
		f_surface_fill顶点数据(m_GPU可视网格, 空间坐标);
		//std::cout << "data = " << data.size() << std::endl;
		break;
	}

	case E_值类型::e_Type_Vec2: {

		break;
	}

	/*case E_值类型::e_插座Type_Vec3: {
		const auto& point = *((vec3*)输入数据.m_Data);

		std::vector<vec3> 射线(2);
		射线[0] = 射线起点;
		射线[1] = 射线终点;
		f_surface_fill顶点数据(m_GPU可视网格, { point });

		break;
	}*/

	case E_值类型::e_Type_Vec3_Array1D: {
		const auto& point = *((std::vector<vec3>*)输入数据.m_Data);

		uint32 num = point.size();
		auto* data = point.data();
		
		std::vector<vec3> 拾取数据;
		for (uint32 k = 0; k < 射线数量; ++k) {
			vec3 射线起点 = 射线[k * 2];
			dir = vec_normalize2(射线[k * 2 + 1] - 射线起点);

			for (uint32 i = 0; i < num; ++i) {
				float32 碰撞距离 = f_射线与点相交(射线起点, dir, { data[i], 1.0 });
				if (碰撞距离 > 0.0) {
					拾取数据.push_back(data[i]);
				}
			}
		}

		f_surface_fill顶点数据(m_GPU可视网格, 拾取数据);
		break;
	}

	case E_值类型::e_Type_Vec2_Array1D: {

		break;
	}

	

	default:
		break;
	}

	return false;
}






C_节点基类* f_node_载入射线拾取节点(S_设备环境& ctx, FILE* f) {
	C_射线拾取节点* node = new C_射线拾取节点(ctx);

	return node;
}

void f_node_保存射线拾取节点(C_节点基类* n, FILE* f) {
	C_射线拾取节点* node = dynamic_cast<C_射线拾取节点*>(n);
}










C_范围拾取节点::C_范围拾取节点(S_设备环境& ctx) : C_节点基类("范围拾取节点") {
	m_Name = L"范围拾取";
	m_GPU环境 = ctx;
	m_输入的数据类型 = E_值类型::e_Type_None;

	m_GPU可视网格 = f_surface_创建网格对象(nullptr, m_GPU环境, E_网格数据枚举::e_Mesh_VULKAN);
	m_GPU射线可视网格 = f_surface_创建网格对象(nullptr, m_GPU环境, E_网格数据枚举::e_Mesh_VULKAN);


	C_插座基类* socket;
	DEF_创建引用插座_I(L"容器");
	//DEF_创建Vec球_1D_插座_I("范围");
	DEF_创建引用插座_I(L"范围");


	DEF_创建树路径插座_O(L"拾取空间");
	DEF_创建引用插座_O(L"拾取");
}

C_范围拾取节点::~C_范围拾取节点() {
	
}

bool C_范围拾取节点::f_update() {
	auto& 输入数据 = *DEF_引用插座数据(f_get输入插座(1), 0);
	//auto& 范围数据 = *DEF_Vec球_1D_插座数据(f_get输入插座(2), 0);
	auto& in数据2 = *DEF_引用插座数据(f_get输入插座(2), 0);

	auto& 空间树 = *DEF_树路径插座Value(f_get输出插座(1), 0);
	空间树.clear();


	uint32 范围数量 = 0;
	//S_VecSphere* 范围 = 范围数据.data();

	m_输入的数据类型 = 输入数据.m_Type;
	switch (输入数据.m_Type) {
	case E_值类型::e_插座Type_八叉树: {
		auto* tree = ((S_点距八叉树*)输入数据.m_Data);

		switch (in数据2.m_Type) {
		case E_值类型::e_Type_VecSphere_1D: {
			S_VecSphere* 范围 = (*((std::vector<S_VecSphere>*)in数据2.m_Data)).data();
			范围数量 = (*((std::vector<S_VecSphere>*)in数据2.m_Data)).size();

			std::vector<vec4> 空间坐标;
			for (uint32 k = 0; k < 范围数量; ++k) {
				f_空间划分_get范围子集数据(tree, 范围[k], 空间树, true);
				//f_空间划分_范围拾取解析为域坐标(tree, 范围[k], 空间坐标);
			}

			break;
		}

		case E_值类型::e_插座Type_Line_Array1D: {
			f_范围索取树单元数据(*tree, *((std::vector<S_线段>*)in数据2.m_Data), 空间树);
			break;
		}
		}
		//f_surface_填充顶点数据(m_GPU可视网格, 空间坐标);
		break;
	}

	case E_值类型::e_Type_Vec2: {

		break;
	}

	case E_值类型::e_Type_Vec3_Array1D: {
		const auto& point = *((std::vector<vec3>*)输入数据.m_Data);

		uint32 num = point.size();
		auto* data = point.data();

		switch (in数据2.m_Type) {
		case E_值类型::e_Type_VecSphere_1D: {
			S_VecSphere* 范围 = (*((std::vector<S_VecSphere>*)in数据2.m_Data)).data();
			范围数量 = (*((std::vector<S_VecSphere>*)in数据2.m_Data)).size();

			std::vector<vec3> 拾取数据;
			for (uint32 k = 0; k < 范围数量; ++k) {
				for (uint32 i = 0; i < num; ++i) {
					float32 距离 = vec_len(point[i] - 范围[k].pos);

					if (距离 <= 范围[k].radius) {
						拾取数据.push_back(data[i]);
					}
				}
			}
			//f_surface_fill顶点数据(m_GPU可视网格, 拾取数据);
			break;
		}
		}

		
		break;
	}

	case E_值类型::e_Type_Vec2_Array1D: {

		break;
	}



	default:
		break;
	}

	return false;
}

void C_范围拾取节点::f_范围索取树单元数据(const S_点距八叉树& tree, const std::vector<S_线段>& lines, std::vector<S_八叉树子空间*>& pathTree) {
	uint32 lineNum = lines.size();
	const S_线段* p_lines = lines.data();

	for (uint32 i = 0; i < lineNum; ++i) {
		f_空间划分_线段查子空间(&tree, p_lines[i], pathTree);
	}

}

C_节点基类* f_node_载入范围拾取节点(S_设备环境& ctx, FILE* f) {
	C_范围拾取节点* node = new C_范围拾取节点(ctx);

	return node;
}

void f_node_保存范围拾取节点(C_节点基类* n, FILE* f) {
	C_范围拾取节点* node = dynamic_cast<C_范围拾取节点*>(n);
}





















